package net.dntuan.greeting;

import com.lowagie.text.*;
import com.lowagie.text.pdf.*;
import java.util.*;
import java.io.*;
import java.awt.Color;

public class SimpleToc extends PdfPageEventHelper {

    public ArrayList list = new ArrayList();
    public HashMap map = new HashMap();
    public int pageOffset;
    public boolean roman = false;
    private final static int rn_value[] = {
        1, 4, 5, 9, 10,
        40, 50, 90, 100, 400,
        500, 900, 1000
    };
    private final static String rn_string[] = {
        "I", "IV", "V", "IX", "X",
        "XL", "L", "XC", "C", "CD",
        "D", "CM", "M"
    };

    public static String romanValue(int value) {
        String romaval = "";
        int value_left = value;
        for (int i = rn_value.length - 1; i >= 0; i--) {
            while (rn_value[i] <= value_left) {
                romaval += rn_string[i];
                value_left -= rn_value[i];
            }
        }
        return romaval.toLowerCase();
    }

    public static void textLine(PdfContentByte cb, float y, float left, float right, String connect, Font fontConnect, Phrase phraseLeft, Phrase phraseRight, PdfAction link) {
        float phraseLeftWidth = ColumnText.getWidth(phraseLeft);
        float phraseRightWidth = ColumnText.getWidth(phraseRight);
        float widthRemaining = right - left - phraseRightWidth - phraseLeftWidth;
        ColumnText.showTextAligned(cb, Element.ALIGN_LEFT, phraseLeft, left, y, 0);
        if (connect != null) {
            float cw = ColumnText.getWidth(new Phrase(connect, fontConnect));
            int rep = (int) (widthRemaining / cw);
            if (rep > 0) {
                StringBuffer sb = new StringBuffer();
                for (int k = 0; k < rep; ++k) {
                    sb.append(connect);
                }
                ColumnText.showTextAligned(cb, Element.ALIGN_RIGHT, new Phrase(sb.toString(), fontConnect), right - phraseRightWidth, y, 0);
            }
        }
        ColumnText.showTextAligned(cb, Element.ALIGN_RIGHT, phraseRight, right, y, 0);
        if (link != null) {
            cb.setAction(link, left, y, right, y + 12);
        }
    }

    public static void main(String[] args) {
        try {
            Document doc = new Document(PageSize.A4, 72, 72, 72, 72);
            PdfWriter writer = PdfWriter.getInstance(doc, new FileOutputStream("d:\\simple_toc.pdf"));
            SimpleToc toc = new SimpleToc();
            toc.pageOffset = 0;
            writer.setPageEvent(toc);
            String text = "Some text lines ";
            for (int k = 0; k < 7; ++k) {
                text += text;
            }
            doc.open();
            Font font = new Font(Font.TIMES_ROMAN, 16, Font.NORMAL, Color.red);
            writer.setLinearPageMode();
            for (int k = 1; k < 500; ++k) {
                String level = "" + k;
                String txt_level = "The clickable header level " + level + " goes here";
                Chunk ck = new Chunk(txt_level, font).setGenericTag(level);
                Object obj[] = new Object[3];
                obj[0] = ck;
                toc.list.add(level);
                toc.map.put(level, obj);
                doc.add(new Paragraph(ck));
                doc.add(new Paragraph(text));
            }
            doc.newPage();
            PdfContentByte cb = writer.getDirectContent();
            int split = writer.getPageNumber();
            PdfOutline rootOutline = cb.getRootOutline();
            PdfAction linkTOC = PdfAction.gotoLocalPage(split, new PdfDestination(PdfDestination.XYZ, 0, 10000, 0), writer);
            new PdfOutline(rootOutline, linkTOC, "Table Of Contents");
            toc.roman = true;
            toc.pageOffset = 1 - split;
            float top = doc.top();
            float bottom = doc.bottom();
            float left = doc.left();
            float right = doc.right();

            ColumnText.showTextAligned(cb, Element.ALIGN_CENTER,
                    new Phrase("Table Of Contents", new Font(Font.HELVETICA, 24)), (left + right) / 2, top - 24, 0);

            float offset = top - 48;
            for (int k = 0; k < toc.list.size(); ++k) {
                Object obj[] = (Object[]) toc.map.get(toc.list.get(k));
                Chunk ck = new Chunk(((Chunk) obj[0]).getContent());
                Rectangle rect = (Rectangle) obj[1];
                String number = (String) obj[2];
                PdfAction link = PdfAction.gotoLocalPage(Integer.parseInt(number), new PdfDestination(PdfDestination.XYZ, rect.getLeft(), rect.getTop(), 0f), writer);
                PdfAction link2 = PdfAction.gotoLocalPage(Integer.parseInt(number), new PdfDestination(PdfDestination.XYZ, rect.getLeft(), rect.getTop(), 0), writer);
                new PdfOutline(rootOutline, link2, ck.getContent());
                textLine(cb, offset, left, right, " .", new Font(), new Phrase(ck), new Phrase(number), link);
                offset -= 16;
                if (offset < bottom) {
                    offset = top - 16;
                    doc.newPage();
                }
            }

            doc.newPage();
            int totalPages = writer.getPageNumber() - 1;
            int reorder[] = new int[totalPages];
            for (int k = split; k <= totalPages; ++k) {
                reorder[k - split] = k;
            }
            int off = totalPages - split;
            for (int k = 1; k < split; ++k) {
                reorder[off + k] = k;
            }
            writer.reorderPages(reorder);
            PdfPageLabels pageLabels = new PdfPageLabels();
            pageLabels.addPageLabel(1, PdfPageLabels.LOWERCASE_ROMAN_NUMERALS);
            pageLabels.addPageLabel(totalPages - split + 2, PdfPageLabels.DECIMAL_ARABIC_NUMERALS);
            writer.setPageLabels(pageLabels);
            writer.setViewerPreferences(PdfWriter.PageModeUseOutlines);
            doc.close();
            System.out.println("Finished.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void onGenericTag(PdfWriter writer, Document document, Rectangle rect, String text) {
        Object obj[] = (Object[]) map.get(text);
        obj[1] = rect;
        obj[2] = "" + writer.getPageNumber();
    }

    public void onEndPage(PdfWriter writer, Document document) {
        try {
            int n = pageOffset + writer.getPageNumber();
            String ns = null;
            if (roman) {
                ns = romanValue(n);
            } else {
                ns = "" + n;
            }
            ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_CENTER, new Phrase(ns), (document.right() + document.left()) / 2, document.bottom() - 20, 0);
        } catch (Exception e) {
            throw new ExceptionConverter(e);
        }
    }
}
